﻿using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

using RiskCalc.Modelo;

namespace RiskCalc.Persistencia
{
    public class Persistencia
    {
        public static string CONST_NOME_ARQUIVO_XLSX = "DadosAcoes.xlsx";
        public static string CONST_NOME_PLANILHA_GERADA = "DadosGerados";

        public static bool carregarDadosDoBanco(Carteira carteira, out string msgRetorno)
        {
            //// Acessa o root do projeto, pois o método Open() a seguir não aceita path relativo
            string pathArquivoExcel = Environment.CurrentDirectory.Replace("bin\\Debug", "");

            // Se não funcionar a troca, tenta denovo com modo "Release"
            if (pathArquivoExcel.Length.Equals(Environment.CurrentDirectory.Length))
            {
                pathArquivoExcel = Environment.CurrentDirectory.Replace("bin\\Release", "");
            }

            // RELEASE
            //string pathArquivoExcel = Environment.CurrentDirectory + @"\";

            // Se não funcionar novamente, é pq está no mesmo path do exe, logo não precisa trocar
            OleDbConnection connection = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + pathArquivoExcel + CONST_NOME_ARQUIVO_XLSX + ";Extended Properties=&quot;Excel 12.0 Xml;HDR=YES&quot;");

            OleDbCommand command1 = new OleDbCommand("SELECT * FROM [Valores$];", connection);
            OleDbCommand command2 = new OleDbCommand("SELECT * FROM [Quantidades$];", connection);

            connection.Open();

            ////////////////////////////////////////////////////////////////////////////////////
            // Obtém as ações e seus dados
            ////////////////////////////////////////////////////////////////////////////////////
            OleDbDataReader reader1 = command1.ExecuteReader();

            carteira.vetAcao = new List<Acao>();
            Dado dado = null;
            Acao acao = null;

            while (reader1.Read())
            {
                if (acao == null || acao.Nome != reader1.GetString(1))
                {
                    acao = new Acao();
                    acao.Nome = reader1.GetString(1);
                    carteira.vetAcao.Add(acao);
                }

                dado = new Dado();
                dado.Acao = acao;
                dado.Valor = reader1.GetDouble(2);
                dado.Dia = reader1.GetDateTime(0);
                acao.VetDados.Add(dado);
            }

            reader1.Close();


            ////////////////////////////////////////////////////////////////////////////////////
            // Obtém as quantidades
            ////////////////////////////////////////////////////////////////////////////////////
            OleDbDataReader reader2 = command2.ExecuteReader();

            while (reader2.Read())
            {
                acao = carteira.vetAcao.Find(acaoAux => acaoAux.Nome.Equals(reader2.GetString(0)));
                acao.Quantidade = Convert.ToInt32(reader2.GetDouble(1));
            }

            reader2.Close();

            msgRetorno = "Sucesso";
            return true;
        }

        // http://msdn.microsoft.com/en-us/library/xyhf0ksb.aspx
        public static bool imprimirNoExcel(Carteira carteira, out string msgRetorno, bool imprimirDebug)
        {
            ApplicationClass ExcelApp;
            Workbook objBook;
            Worksheet objSheet;

            object missing = System.Reflection.Missing.Value;

            ExcelApp = new ApplicationClass();
            ExcelApp.Visible = true;
            ExcelApp.UserControl = true;

            // (RELEASE) Acessa o root do projeto, pois o método Open() a seguir não aceita path relativo
            //string pathArquivoExcel = Environment.CurrentDirectory + @"\";

            //// Acessa o root do projeto, pois o método Open() a seguir não aceita path relativo
            string pathArquivoExcel = Environment.CurrentDirectory.Replace("bin\\Debug", "");

            // Se não funcionar a troca, tenta denovo com modo "Release"
            if (pathArquivoExcel.Length.Equals(Environment.CurrentDirectory.Length))
            {
                pathArquivoExcel = Environment.CurrentDirectory.Replace("bin\\Release", "");
            }

            // Se não funcionar a troca, o arquivo Excel está no mesmo diretório que o executável, logo apenas adiciona "\"
            if (pathArquivoExcel.Length.Equals(Environment.CurrentDirectory.Length))
            {
                pathArquivoExcel += @"\";
            }

            // Tenta abrir o arquivo
            try
            {
                objBook = ExcelApp.Workbooks.Open(pathArquivoExcel + CONST_NOME_ARQUIVO_XLSX,
                    missing, missing, missing, missing, missing, missing, missing,
                    missing, missing, missing, missing, missing, missing, missing);
            }
            catch (COMException)
            {
                msgRetorno = "Arquivo " + CONST_NOME_ARQUIVO_XLSX + " não encontrado. Ele deve estar na raiz do projeto.";
                return false;
            }

            // Cria nova planilha como "Plan1"
            objSheet = (Worksheet)objBook.Worksheets.Add(missing, missing, missing, missing);

            // Gera o novo nome para "Plan1"
            string nomeUltimaPlanilha = ((Worksheet)ExcelApp.Worksheets[2]).Name;
            int ultimoNumeroPlanilha = 1;

            // Tenta renomear a planilha
            try
            {
                // Se não for a primeira vez
                if (!nomeUltimaPlanilha.Equals("Valores") && !nomeUltimaPlanilha.Equals("Quantidades") && !nomeUltimaPlanilha.Equals("VaR"))
                {
                    // Obtém o último numero
                    ultimoNumeroPlanilha = Convert.ToInt16(nomeUltimaPlanilha.Substring(CONST_NOME_PLANILHA_GERADA.Length, (nomeUltimaPlanilha.Length - CONST_NOME_PLANILHA_GERADA.Length)));

                    // Gera com o próximo número "ComparativoN"
                    objSheet.Name = CONST_NOME_PLANILHA_GERADA + (ultimoNumeroPlanilha + 1);
                }
                else
                {
                    // Se for a primeira vez
                    objSheet.Name = CONST_NOME_PLANILHA_GERADA + ultimoNumeroPlanilha;
                }
            }
            catch (COMException)
            {
                msgRetorno = "Erro na numeração da nova planilha gerada.";
                return false;
            }

            try
            {
                // Define formatação das colunas
                objSheet.get_Range("A1", "A1").EntireColumn.ColumnWidth = 9.57;
                objSheet.get_Range("B1", "B1").EntireColumn.ColumnWidth = 14;
                objSheet.get_Range("C1", "C1").EntireColumn.ColumnWidth = 15;
                objSheet.get_Range("D1", "D1").EntireColumn.ColumnWidth = 15;
                objSheet.get_Range("F1", "F1").EntireColumn.ColumnWidth = 8;
                objSheet.get_Range("G1", "G1").EntireColumn.ColumnWidth = 12;
                objSheet.get_Range("H1", "H1").EntireColumn.ColumnWidth = 9;
                objSheet.get_Range("I1", "I1").EntireColumn.ColumnWidth = 18;
                objSheet.get_Range("J1", "J1").EntireColumn.ColumnWidth = 18;
                objSheet.get_Range("K1", "K1").EntireColumn.ColumnWidth = 14;

                objSheet.get_Range("B1", "D1").EntireColumn.NumberFormat = "#.##0,00";
                objSheet.get_Range("I1", "J1").EntireColumn.NumberFormat = "0,000%";
                objSheet.get_Range("H1", "H1").EntireColumn.NumberFormat = "#.##0,00";
                objSheet.get_Range("K1", "K1").EntireColumn.NumberFormat = "#.##0,00";
                objSheet.get_Range("M2", "AF20").EntireColumn.NumberFormat = "#.##0,00";

                objSheet.get_Range("A1", "AE1").Font.Bold = true;
                objSheet.get_Range("M23", "M23").Font.Bold = true;
                objSheet.get_Range("A1", "K1").EntireColumn.HorizontalAlignment = XlVAlign.xlVAlignCenter;

                objSheet.get_Range("A1", "AF1").BorderAround(XlLineStyle.xlContinuous,
                           XlBorderWeight.xlMedium, XlColorIndex.xlColorIndexAutomatic,
                           XlColorIndex.xlColorIndexAutomatic);

                // Preenche os cabeçalhos
                objSheet.Cells[1, 1] = "Ação";
                objSheet.Cells[1, 2] = "VaR Aritmético";
                objSheet.Cells[1, 3] = "VaR Geométrico";
                objSheet.Cells[1, 4] = "VaR Histórico";

                // Preenche os VaRs
                for (int i = 0; i < carteira.vetAcao.Count; i++)
                {
                    //objSheet.Cells[i + 2, 1] = carteira.vetAcao[i].Nome;
                    //objSheet.Cells[i + 2, 2] = carteira.vetAcao[i].desvioPadrao;
                    //objSheet.Cells[i + 2, 3] = carteira.vetAcao[i].VarParametrico;
                    //objSheet.Cells[i + 2, 4] = carteira.vetAcao[i].VarHistorico;
                }

                objSheet.Cells[1, 13] = "Matriz de Correlação de Retornos Aritméticos";

                // Preenche a matriz de correlação aritmetica
                for (int i = 0; i < carteira.vetAcao.Count; i++)
                {
                    for (int j = 0; j < carteira.vetAcao.Count; j++)
                    {
                        //objSheet.Cells[j + 3, i + 14] = carteira.matrizCovariancia[i, j];
                    }

                    objSheet.Cells[2, i + 14] = carteira.vetAcao[i].Nome;
                    objSheet.Cells[i + 3, 13] = carteira.vetAcao[i].Nome;
                }

                objSheet.Cells[23, 13] = "Matriz de Correlação de Retornos Geométricos";

                // Preenche a matriz de correlação geométrica
                for (int i = 0; i < carteira.vetAcao.Count; i++)
                {
                    for (int j = 0; j < carteira.vetAcao.Count; j++)
                    {
                        //objSheet.Cells[j + 25, i + 14] = carteira.matrizCorrelacao[i, j];
                    }

                    objSheet.Cells[24, i + 14] = carteira.vetAcao[i].Nome;
                    objSheet.Cells[i + 25, 13] = carteira.vetAcao[i].Nome;
                }

                objSheet.Cells[1, 6] = "Ação";
                objSheet.Cells[1, 7] = "Dia";
                objSheet.Cells[1, 8] = "Valor";
                objSheet.Cells[1, 9] = "Retorno Aritmético";
                objSheet.Cells[1, 10] = "Retorno Geométrico";
                objSheet.Cells[1, 11] = "Perda ou Ganho";

                // Preenche os retornos
                for (int i = 0; i < carteira.vetAcao.Count; i++)
                {
                    for (int j = 0; j < carteira.vetAcao[i].VetDados.Count; j++)
                    {
                        objSheet.Cells[(i * carteira.vetAcao[i].VetDados.Count) + j + 2, 6] = carteira.vetAcao[i].Nome;
                        objSheet.Cells[(i * carteira.vetAcao[i].VetDados.Count) + j + 2, 7] = carteira.vetAcao[i].VetDados[j].Dia.ToString("dd/MM/yy");
                        objSheet.Cells[(i * carteira.vetAcao[i].VetDados.Count) + j + 2, 8] = carteira.vetAcao[i].VetDados[j].Valor;
                        //objSheet.Cells[(i * carteira.vetAcao[i].VetDados.Count) + j + 2, 9] = carteira.vetAcao[i].VetDados[j].RetornoAritmetico;
                        objSheet.Cells[(i * carteira.vetAcao[i].VetDados.Count) + j + 2, 10] = carteira.vetAcao[i].VetDados[j].RetornoGeometrico;
                        //objSheet.Cells[(i * carteira.vetAcao[i].VetDados.Count) + j + 2, 11] = carteira.vetAcao[i].VetDados[j].PerdaOuGanho;
                    }
                }

                msgRetorno = "Sucesso";
                return true;
            }
            catch (COMException)
            {
                msgRetorno = "Geração de Relatório no Excel interrompida por clique do usuário.";
                return false;
            }
        }
    }
}